import router from '~/router'
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'
import { IResponseData } from '~/types/IResponseData'
import { userStore } from '~/store'
import msgUtil from '../message'

const baseUrl = '/api'

class Http {
  service

  constructor() {
    this.service = axios.create({
      baseURL: baseUrl,
      withCredentials: true,
      timeout: 10000,
      transformResponse: [
        (data) => {
          if (typeof data === 'string' && data.startsWith('{')) {
            data = JSON.parse(data)
          }
          return data
        }
      ]
    })

    /* 请求拦截  this.service.interceptors.request.use(config => config, error => Promise.reject(error))*/
    this.service.interceptors.request.use(
      (request: AxiosRequestConfig) => {
        const user = userStore()
        request.headers['Authorization'] = user.token
        return request
      },
      (error) => {
        return Promise.reject(error) // 为了可以在代码中catch到错误信息
      }
    )

    /* 响应拦截   this.service.interceptors.response.use(response => response.data, error => Promise.reject(error))*/
    this.service.interceptors.response.use(
      (response: AxiosResponse<any>) => {
        const { data } = response
        if (data instanceof Blob) {
          //'application/octet-stream' 'image/png' 等
          return response
        }
        if (!data.success) {
          msgUtil.error(data.message)
          return Promise.reject(data)
        }
        return data
      },
      async (error) => {
        const response = error.response
        if (response.status === 403 || response.status === 403) {
          await router.push('/login')
        } else {
          msgUtil.error(response.data.message)
        }
        return Promise.reject(response)
      }
    )
  }

  get<T>(url: string, params?: object, _object = {}): Promise<IResponseData<T>> {
    return this.service.get(url, { params, ..._object })
  }

  downloadFileViaGet(url: string): Promise<void> {
    return this.service({
      method: 'get',
      url,
      responseType: 'blob'
    }).then((res) => {
      const { data, headers } = res
      const fileName = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1')
      // 此处当返回json文件时需要先对data进行JSON.stringify处理，其他类型文件不用做处理
      //const blob = new Blob([JSON.stringify(data)], ...)
      const blob = new Blob([data], { type: headers['content-type'] })
      const dom = document.createElement('a')
      const url = window.URL.createObjectURL(blob)
      dom.href = url
      dom.download = decodeURI(fileName)
      dom.style.display = 'none'
      document.body.appendChild(dom)
      dom.click()
      dom.parentNode.removeChild(dom)
      window.URL.revokeObjectURL(url)
    })
  }

  downloadFileViaPost(url: string, params?: object): Promise<void> {
    return this.service({
      method: 'post',
      url: url,
      data: params,
      responseType: 'blob'
    }).then((res) => {
      const { data, headers } = res
      const fileName = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1')
      // 此处当返回json文件时需要先对data进行JSON.stringify处理，其他类型文件不用做处理
      //const blob = new Blob([JSON.stringify(data)], ...)
      const blob = new Blob([data], { type: headers['content-type'] })
      const dom = document.createElement('a')
      const url = window.URL.createObjectURL(blob)
      dom.href = url
      dom.download = decodeURI(fileName)
      dom.style.display = 'none'
      document.body.appendChild(dom)
      dom.click()
      dom.parentNode.removeChild(dom)
      window.URL.revokeObjectURL(url)
    })
  }

  getImage(url: string): Promise<string> {
    return new Promise<string>((resolve) => {
      this.service({
        method: 'get',
        url,
        responseType: 'blob'
      }).then((res) => {
        const { data, headers } = res
        const blob = new Blob([data], { type: headers['content-type'] })
        const url = window.URL.createObjectURL(blob)
        resolve(url)
      })
    })
  }

  post<T>(url: string, params?: object, _object = {}): Promise<IResponseData<T>> {
    return this.service.post(url, params, _object)
  }

  put<T>(url: string, params?: object, _object = {}): Promise<IResponseData<T>> {
    return this.service.put(url, params, _object)
  }

  delete<T>(url: string, params?: any, _object = {}): Promise<IResponseData<T>> {
    return this.service.delete(url, { params, ..._object })
  }
}

export default new Http()
